﻿namespace Bildverarbeitung.CGFilter
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Drawing;
    using System.Drawing.Imaging;

    /// <summary>
    /// 
    /// </summary>
    public class EnglertMichael : Bildverarbeitung.IFilter
    {
        /// <summary>
        /// Gets the summerized difference from average of all images.
        /// </summary>
        /// <param name="images">Given images.</param>
        /// <returns>The summerized difference.</returns>
        public Bitmap GetSummerizedDifferencefromAverage(Bitmap[] images)
        {
            if (images.Length < 1)
            {
                return null;
            }
            else
            {
                return Filter(GetAVGBitmap(images, images[0].Width, images[0].Height), images, images[0].Width, images[0].Height);
            }
        }

        public Bitmap Filter(Bitmap avgBitmap, Bitmap[] bitmaps, int width, int height)
        {
            // Daten der Durchschnitts-Bitmap locken
            BitmapData resultBitmapData = avgBitmap.LockBits(new Rectangle(0, 0, width, height),
                                          ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            // Speicher für die BitmapData-Objekte der übergebenen Bitmaps
            BitmapData[] bitmapDatas = new BitmapData[bitmaps.Length];

            unsafe
            {
                // Start-Pointer des Ergebnisbildes erzeugen
                byte* resultBitmapPtr = (byte*)resultBitmapData.Scan0.ToPointer();
                // Speicher für die Pointer jeder übergebenen Bitmap
                byte*[] bitmapPtrs = new byte*[bitmaps.Length];

                // Alle Bitmaps locken und Pointer erzeugen
                for (int i = 0; i < bitmaps.Length; i++)
                {
                    bitmapDatas[i] = bitmaps[i].LockBits(new Rectangle(0, 0, width, height),
                                          ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                    bitmapPtrs[i] = (byte*)bitmapDatas[i].Scan0.ToPointer();
                }

                // Berechnung des Durchschnittsbildes
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < (width * 3); x++)
                    {
                        // RGB Variablen für die Durchschnittsberechnung anlegen
                        int avgTop = 0, avgBottom = 0, avgBottomCounter = 0, avgTopCounter = 0, value = 0;

                        for (int i = 0; i < bitmaps.Length; i++)
                        {
                            value = ((int)*bitmapPtrs[i]);
                            if (value > ((int)*resultBitmapPtr))
                            {
                                avgTop += value;
                                avgTopCounter++;
                            }
                            else
                            {
                                avgBottom += value;
                                avgBottomCounter++;
                            }
                            bitmapPtrs[i]++;
                        }
                        if (avgBottomCounter > avgTopCounter)
                            *resultBitmapPtr = (byte)(avgBottom / avgBottomCounter);
                        else
                            *resultBitmapPtr = (byte)(avgTop / avgTopCounter);
                        resultBitmapPtr++;
                    }
                }
            }

            // Gesamte Bilddaten wieder frei geben
            for (int i = 0; i < bitmaps.Length; i++)
                bitmaps[i].UnlockBits(bitmapDatas[i]);
            avgBitmap.UnlockBits(resultBitmapData);

            // berechnetes Bild zurück geben
            return avgBitmap;
        }



        public Bitmap GetAVGBitmap(Bitmap[] bitmaps, int width, int height)
        {
            // Ergebnis Bitmap erzeugen und im Speicher sperren
            Bitmap resultBitmap = new Bitmap(width, height);
            BitmapData resultBitmapData = resultBitmap.LockBits(new Rectangle(0, 0, width, height),
                                          ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            // Speicher für die BitmapData-Objekte der übergebenen Bitmaps
            BitmapData[] bitmapDatas = new BitmapData[bitmaps.Length];

            unsafe
            {
                // Start-Pointer des Ergebnisbildes erzeugen
                byte* resultBitmapPtr = (byte*)resultBitmapData.Scan0.ToPointer();
                // Speicher für die Pointer jeder übergebenen Bitmap
                byte*[] bitmapPtrs = new byte*[bitmaps.Length];

                // Alle Bitmaps locken und Pointer erzeugen
                for (int i = 0; i < bitmaps.Length; i++)
                {
                    bitmapDatas[i] = bitmaps[i].LockBits(new Rectangle(0, 0, width, height),
                                          ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                    bitmapPtrs[i] = (byte*)bitmapDatas[i].Scan0.ToPointer();
                }

                // Berechnung des Durchschnittsbildes
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        // RGB Variablen für die Durchschnittsberechnung anlegen
                        int B = 0, G = 0, R = 0;
                        for (int i = 0; i < bitmaps.Length; i++)
                        {
                            B += ((int)*bitmapPtrs[i]);
                            bitmapPtrs[i]++;
                            G += ((int)*bitmapPtrs[i]);
                            bitmapPtrs[i]++;
                            R += ((int)*bitmapPtrs[i]);
                            bitmapPtrs[i]++;
                        }

                        *resultBitmapPtr = (byte)(B / (bitmaps.Length));
                        resultBitmapPtr++;
                        *resultBitmapPtr = (byte)(G / (bitmaps.Length));
                        resultBitmapPtr++;
                        *resultBitmapPtr = (byte)(R / (bitmaps.Length));
                        resultBitmapPtr++;
                    }
                }
            }

            // Gesamte Bilddaten wieder frei geben
            for (int i = 0; i < bitmaps.Length; i++)
                bitmaps[i].UnlockBits(bitmapDatas[i]);
            resultBitmap.UnlockBits(resultBitmapData);

            // berechnetes Bild zurück geben
            return resultBitmap;
        }

        /// <summary>
        /// Return the author´s name
        /// Please use NachnameVorname (without spaces).
        /// </summary>
        /// <returns>author´s name</returns>
        public String GetName()
        {
            return ("EnglertMichael");
        }
    }
}
